
#include <bits/types/struct_timeval.h>
#include <cstdint>
#include <ctime>
#include <gtest/gtest.h>
#include <sys/timerfd.h>
#include <sys/time.h>
#include <unistd.h>
#include "../loop.h"
#include "./../../log_module/log_module_define.h"

#define TIME_INTERVAL 10

TEST(TimerFd, test)
{

    int timer_fd = timerfd_create(CLOCK_REALTIME, 0);
    struct itimerspec time_value{};
    struct timeval now_time{};
    gettimeofday(&now_time, nullptr);

    time_value.it_value.tv_sec = now_time.tv_sec + TIME_INTERVAL + 10;
    time_value.it_value.tv_nsec = 0;

    time_value.it_interval.tv_sec = TIME_INTERVAL;
    time_value.it_interval.tv_nsec = 0;

    int result = timerfd_settime(timer_fd ,TFD_TIMER_ABSTIME, &time_value, nullptr);

    INFO("create timerfd result {}", result);

    for (int index = 0; index < 100; index++)
    {
        int64_t data{};
        int size = read(timer_fd, &data, sizeof(data)); 

        INFO("data size : {} and data content : {}", size, data);
        if (index >= 0)
        {
            struct itimerspec old_time_value{};
            timerfd_gettime(timer_fd, &old_time_value);
            INFO("now : {}:{} next interval : {}:{}", old_time_value.it_value.tv_sec, old_time_value.it_value.tv_nsec, old_time_value.it_interval.tv_sec, old_time_value.it_interval.tv_nsec);
            if (index == 5)
            {
                struct itimerspec new_time_value = old_time_value;
                new_time_value.it_value.tv_sec = 0;
                new_time_value.it_value.tv_nsec = TIME_INTERVAL;
                timerfd_settime(timer_fd, 0, &new_time_value, &old_time_value);
            }
        }
        if (index == 3)
        {
            break;
        }
    }
    close(timer_fd);
}

void TestTask(Loop * loop)
{
    loop->AddPendingTask([loop](){
            
        struct timeval time;
        gettimeofday(&time, nullptr);
        INFO("task time : {}:{}", time.tv_sec, time.tv_usec);
        /* TestTask(loop); */
    });
}

TEST(LoopPendingTask, Test)
{
    Loop loop;
    TestTask(&loop);
    loop.Run();
}

int main(int argc, char * argv[])
{
    testing::InitGoogleTest();
    LogModuleConfig config;
    config.m_log_level = "trace";
    config.m_file_name = argv[0];
    LogModule::Instance()->InitModule(config);
    return RUN_ALL_TESTS();
}
